home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / nihcl-30.lha / nihcl-3.0 / lib / Scheduler.c < prev    next >
C/C++ Source or Header  |  1990-05-19  |  6KB  |  246 lines

  1. /* Scheduler.c -- implementation of the Process Scheduler
  2.  
  3.     THIS SOFTWARE FITS THE DESCRIPTION IN THE U.S. COPYRIGHT ACT OF A
  4.     "UNITED STATES GOVERNMENT WORK".  IT WAS WRITTEN AS A PART OF THE
  5.     AUTHOR'S OFFICIAL DUTIES AS A GOVERNMENT EMPLOYEE.  THIS MEANS IT
  6.     CANNOT BE COPYRIGHTED.  THIS SOFTWARE IS FREELY AVAILABLE TO THE
  7.     PUBLIC FOR USE WITHOUT A COPYRIGHT NOTICE, AND THERE ARE NO
  8.     RESTRICTIONS ON ITS USE, NOW OR SUBSEQUENTLY.
  9.  
  10. Author:
  11.     K. E. Gorlen
  12.     Bg. 12A, Rm. 2033
  13.     Computer Systems Laboratory
  14.     Division of Computer Research and Technology
  15.     National Institutes of Health
  16.     Bethesda, Maryland 20892
  17.     Phone: (301) 496-1111
  18.     uucp: uunet!nih-csl!kgorlen
  19.     Internet: kgorlen@alw.nih.gov
  20.     December, 1985
  21.  
  22. Function:
  23.  
  24. Class Scheduler provides an interface to the single instance of the
  25. process scheduler, scheduler.  The idea of implementing the coroutine
  26. context switch with setjmp(), longjmp(), and alloca() came from
  27. Dave Jones (hpda!sun!megatest!djones@uunet.uu.net).
  28.  
  29. $Log:    Scheduler.c,v $
  30.  * Revision 3.0  90/05/20  00:21:05  kgorlen
  31.  * Release for 1st edition.
  32.  * 
  33. */
  34.  
  35. #include "Process.h"
  36. #include "Scheduler.h"
  37. #include <osfcn.h>
  38.  
  39. JMP_BUF    Scheduler::switcher;        // environment for stack switcher
  40. Process* Scheduler::active_process = 0;
  41. Process* Scheduler::previous_process = 0;
  42. StackProc* Scheduler::main_stack_process = 0;
  43. #ifndef NESTED_TYPES
  44. stackTy* Scheduler::main_stack_bottom = 0;
  45. #else
  46. Process::stackTy* Scheduler::main_stack_bottom = 0;
  47. #endif
  48. unsigned Scheduler::runCount = 0;    // total # of runnable processes 
  49. int Scheduler::ast_level = 0;        // AST nesting level 
  50. LinkedList Scheduler::runList[MAXPRIORITY+1];
  51.  
  52. #ifdef HAVE_SELECT
  53. LinkedList Scheduler::selectList;        // Processes waiting for select(2)
  54. struct timeval Scheduler::selectTimeout;    // timeout on select
  55. #endif
  56.  
  57. #ifdef HAVE_SELECT
  58.  
  59. #include "FDSet.h"
  60. #include <sys/errno.h>
  61.  
  62. #endif
  63.  
  64. extern const int NIHCL_SCHEDCTOR,NIHCL_ILLEGALFCN;
  65.  
  66. void Scheduler::addProcess(Process& p)
  67. {
  68.     p.process_state = Process::RUNNING;
  69.     runList[p.process_priority].addLast(p);
  70.     runCount++;
  71. }
  72.  
  73. void Scheduler::schedule()
  74. {
  75.     if (astActive()) return;
  76.     setjmp_val val = (setjmp_val)SETJMP(active_process->env);
  77.  
  78.     while (YES) {
  79.     switch (val) {
  80.         case schedule_process: {
  81.         AST_DISABLE;
  82.         while (runCount>0) {
  83.             for (register int i=MAXPRIORITY; i>=0; i--) {
  84.             if (runList[i].size() > 0) {
  85.                 Process* active = active_process;
  86.                 Process* next = Process::castdown(runList[i].first());
  87.                 if (active != next) {
  88.                 previous_process = active;
  89.                 active_process = next;
  90.                 active->switchContext(next);
  91.                 }
  92.                 LONGJMP(next->env, resume_current_process);
  93.             }
  94.             }
  95.         }
  96.  
  97. #ifdef HAVE_SELECT
  98.         if (selectList.isEmpty())
  99. #endif
  100.             AST_PAUSE;            // wait for AST/signal
  101. #ifdef HAVE_SELECT
  102.         else selectfd();    // wait for AST, signal, or I/O
  103. #endif
  104.  
  105.         break;    // schedule process
  106.         }
  107.  
  108.         case resume_current_process: return;
  109.  
  110.         case resume_new_process: {
  111.         active_process->restore();
  112.         return;
  113.         }
  114.     }
  115.     }
  116. }
  117.  
  118. #ifdef HAVE_SELECT
  119.  
  120. #include <errno.h>
  121.  
  122. int Scheduler::selectfd()
  123. {
  124.     int mcount =0;            // return value from select(2)
  125.         FDSet rmask, wmask, xmask;
  126.     selectTimeout.tv_sec = 10;
  127.     selectTimeout.tv_usec = 0;
  128.     
  129.     if (selectList.isEmpty() ) return 0;
  130.     register Process* p = Process::castdown(selectList.first());
  131.     
  132.     while (!p->isListEnd()) {    // build select masks
  133.         rmask |= p->rdmask;
  134.         wmask |= p->wrmask;
  135.         xmask |= p->exmask;
  136.         p = (Process*)p->nextLink();
  137.     };
  138.  
  139.     AST_RESTORE(0);
  140. /*
  141. If a signal/AST occurs at this point that makes a process runnable (by
  142. calling Process::resume()), it will clear selectTimeout and the
  143. following select will return immediately.  There may still be a window
  144. in which the runnable process will not be scheduled until after this
  145. select returns.  Thus, the select must be done with a timeout.  A
  146. better approach is to use asynchronous I/O instead of select, but this
  147. is said to have bugs under 4.2 BSD.
  148. */
  149.     mcount = ::select(FDSet::dtablesize(),rmask,wmask,xmask,&selectTimeout);
  150.     AST_DISABLE;
  151.  
  152.     if (mcount < 0) { // error
  153.         if (errno == EINTR) return mcount;
  154.         cerr << "Scheduler: error in select (" << errno << ")\n";
  155.         exit(1);
  156.         };
  157.  
  158.     if (mcount == 0) return 0;    // timeout or no fd selected
  159.  
  160.     p = Process::castdown(selectList.first());
  161.     while (!p->isListEnd()) {    // resume all selected processes
  162. #ifdef BUG_bC3035
  163. // sorry, not implemented: temporary of class <name> with destructor needed in <expr> expression
  164.         if ( !(rmask & p->rdmask).isEmpty()
  165.             || !(wmask & p->wrmask).isEmpty()
  166.             || !(xmask & p->exmask).isEmpty() ) {
  167. #else
  168.         int resume = 0;
  169.         if ( !(rmask & p->rdmask).isEmpty() ) resume++;
  170.     else    if ( !(wmask & p->wrmask).isEmpty() ) resume++;
  171.     else    if ( !(xmask & p->exmask).isEmpty() ) resume++;
  172.         if (resume) {
  173. #endif
  174.             p->rdmask &= rmask;
  175.             p->wrmask &= wmask;
  176.             p->exmask &= xmask;
  177.             selectList.remove(*p);
  178.             p->process_state = Process::RUNNING;
  179.             runList[p->process_priority].addLast(*p);
  180.             runCount++;
  181.         };
  182.         p = (Process*)p->nextLink();
  183.     };
  184.     return mcount;
  185. }
  186. #endif
  187.  
  188. void Scheduler::yield()
  189. {
  190.     if (runList[activePriority()].size() == 1) schedule();
  191.     else {
  192.         activeProcess().suspend();
  193.         activeProcess().resume();
  194.     }
  195. }
  196.  
  197. const char* Scheduler::className()    { return "Scheduler"; }
  198.  
  199. void Scheduler::dumpOn(ostream& strm)
  200. {
  201.     AST_DISABLE;
  202.     strm << className()
  203.         << "[active process: "
  204.         << (active_process ? active_process->name() : "NONE")
  205.         << "  previous process: "
  206.         << (previous_process ? previous_process->name() : "NONE")
  207.         << '\n';
  208.     strm << "runList:\n";
  209.     for (register i =MAXPRIORITY; i>=0; i--) {
  210.         DO(runList[i],Process,p) p->dumpOn(strm); OD
  211.     }
  212.  
  213. #ifdef HAVE_SELECT
  214.     if (!selectList.isEmpty()) {
  215.         strm << "selectList:\n";
  216.         DO(selectList,Process,p) p->dumpOn(strm); OD
  217.     }
  218. #endif
  219.  
  220.     strm << "]\n";
  221.     AST_ENABLE;
  222. }
  223.  
  224. void Scheduler::printOn(ostream& strm)
  225. {
  226.     AST_DISABLE;
  227.     strm << className()
  228.         << "  active process: " << active_process->name()
  229.         << "  previous process: " << previous_process->name() << '\n';
  230.     strm << "runList:";
  231.     for (register i =MAXPRIORITY; i>=0; i--) {
  232.         DO(runList[i],Process,p) strm << ' ' << *p; OD
  233.     }
  234.     strm << '\n';
  235.  
  236. #ifdef HAVE_SELECT
  237.     if (!selectList.isEmpty()) {
  238.         strm << "selectList:";
  239.         DO(selectList,Process,p) strm << ' ' << *p; OD
  240.         strm << '\n';
  241.     }
  242. #endif
  243.  
  244.     AST_ENABLE;
  245. }
  246.